from urllib3.exceptions import MaxRetryError
from app.celery_task.celery_app import app
import os
from celery.result import AsyncResult
from celery.exceptions import MaxRetriesExceededError
import time
from app.ai_models.ai_completion.ai_completion_exhibition import process_website_link, create_exhibition_info, process_exhibition
import pandas as pd
import json
from datetime import datetime
from sqlalchemy import text
from app.ai_models.ai_completion.ai_completion_exhibition import db


@app.task
def add(x, y):
    return x + y

@app.task(name='ai_completion_exhibition', bind=True, max_retries=3)
def ai_completion_exhibition(self, user_name, chinese_name, official_website):
    """异步执行展会信息AI补全任务"""
    try:
        print(f"开始AI补全任务: 用户={user_name}, 展会={chinese_name}, 官网={official_website}")
        
        # 构建初始数据
        exhibition_null_data = {              
            "exhibition_number": "新增",
            "chinese_name": chinese_name,
            "english_name": "",
            "english_short_name": "",
            "holding_time": "",
            "event_date_end": "",
            "event_date_start": "",
            "continent": "",
            "source_user": user_name,
            "country": "",
            "city": "",
            "frequency": "",
            "industry": "",
            "organizer": "",
            "organizer_en": "",
            "contact_info": "",
            "exhibition_hall": "",
            "exhibition_hall_english": "",
            "official_website": official_website,
            "exhibit_scope": "",
            "description": "",
            "ufi_certified": 0,
            "exhibition_area": "",
            "ai_checked_status": 4,  # 4表示AI补全进行中
            "ai_link_status": 0,
            "ai_link": "",
            "ai_link_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }

        # 先将初始状态存入数据库
        initial_df = pd.DataFrame([exhibition_null_data])
        try:
            db._df_res_to_db(initial_df, "exhibitions")
            print("初始数据插入成功，状态：AI补全进行中")
        except Exception as e:
            print(f"初始数据插入失败: {str(e)}")
            return {"status": False, "error": f"初始数据插入失败: {str(e)}"}

        # 处理官网链接
        print("正在处理官网链接...")
        link_info = process_website_link(exhibition_null_data["official_website"])
        exhibition_null_data.update(link_info)
        print(f"官网链接处理结果: {link_info}")

        # 调用AI接口检查展会信息
        print("开始调用AI补全接口...")
        check_result = create_exhibition_info(
            link=exhibition_null_data["official_website"], 
            exhibition_row=exhibition_null_data,
            mode="chat"
        )
        print(f"AI处理结果: {check_result}")
        
        # 检查结果格式适配
        # 新版函数使用'success'作为状态键，而旧代码使用'status'
        if check_result.get('success', False):
            # 调整结果格式以兼容旧代码
            adjusted_result = {
                'status': True,
                'response': json.dumps(check_result.get('data', {}))
            }
            check_result = adjusted_result
        else:
            # 处理错误情况
            adjusted_result = {
                'status': False,
                'error': check_result.get('error', '未知错误')
            }
            check_result = adjusted_result
        
        if check_result['status']:
            try:
                # 从response中提取数据
                response_text = check_result['response']
                
                # 如果响应为空，标记为失败
                if not response_text or not response_text.strip():
                    print("AI返回了空响应，无法处理")
                    _update_ai_status_failed(chinese_name, "AI返回了空响应")
                    return {"status": False, "error": "AI返回了空响应"}
                    
                # 如果响应包含markdown代码块，提取其中的JSON
                json_str = ""
                result_data = None
                
                try:
                    if '```json' in response_text:
                        json_start = response_text.find('```json\n') + 8
                        json_end = response_text.rfind('```')
                        if json_start != -1 and json_end != -1:
                            json_str = response_text[json_start:json_end].strip()
                            result_data = json.loads(json_str)
                        else:
                            json_str = response_text
                            result_data = json.loads(response_text)
                    else:
                        json_str = response_text
                        result_data = json.loads(response_text)
                    
                    print(f"成功解析JSON数据: {json_str[:100]}...")
                except json.JSONDecodeError as e:
                    print(f"JSON解析错误: {str(e)}")
                    print(f"原始响应文本: {response_text}")
                    
                    # 尝试移除非JSON字符并再次解析
                    try:
                        # 尝试查找可能的JSON部分
                        possible_json_start = response_text.find('{')
                        possible_json_end = response_text.rfind('}') + 1
                        
                        if possible_json_start != -1 and possible_json_end > possible_json_start:
                            fixed_json = response_text[possible_json_start:possible_json_end]
                            print(f"尝试修复后的JSON: {fixed_json}")
                            result_data = json.loads(fixed_json)
                            print("修复JSON解析成功")
                        else:
                            raise Exception("无法找到有效的JSON内容")
                    except Exception as inner_e:
                        print(f"尝试修复JSON失败: {str(inner_e)}")
                        _update_ai_status_failed(chinese_name, f"JSON解析失败: {str(e)}")
                        return {"status": False, "error": f"JSON解析错误: {str(e)}"}

                # 检查是否成功解析出数据
                if not result_data:
                    print("无法从响应中提取有效数据")
                    _update_ai_status_failed(chinese_name, "无法从响应中提取有效数据")
                    return {"status": False, "error": "无法从响应中提取有效数据"}

                # 更新AI补全状态和链接信息
                result_data.update({
                    'ai_checked_status': 5,  # 5表示AI补全完成
                    'ai_link_status': link_info['ai_link_status'],
                    'ai_link': link_info['ai_link'],
                    'ai_link_time': link_info['ai_link_time']
                })
                
                print("最终数据:", result_data)
                
                try:
                    # 使用text()函数创建SQL语句
                    update_sql = text("""
                    UPDATE exhibitions 
                    SET 
                        english_name = :english_name,
                        english_short_name = :english_short_name,
                        holding_time = :holding_time,
                        event_date_end = :event_date_end,
                        event_date_start = :event_date_start,
                        continent = :continent,
                        country = :country,
                        city = :city,
                        frequency = :frequency,
                        industry = :industry,
                        organizer = :organizer,
                        organizer_en = :organizer_en,
                        contact_info = :contact_info,
                        exhibition_hall = :exhibition_hall,
                        exhibition_hall_english = :exhibition_hall_english,
                        exhibit_scope = :exhibit_scope,
                        description = :description,
                        ufi_certified = :ufi_certified,
                        exhibition_area = :exhibition_area,
                        ai_checked_status = :ai_checked_status,
                        ai_link_status = :ai_link_status,
                        ai_link = :ai_link,
                        ai_link_time = :ai_link_time
                    WHERE chinese_name = :chinese_name
                    """)
                    
                    # 确保所有字段都有值，即使是空字符串
                    update_data = {
                        'english_name': result_data.get('english_name', ''),
                        'english_short_name': result_data.get('english_short_name', ''),
                        'holding_time': result_data.get('holding_time', ''),
                        'event_date_end': result_data.get('event_date_end', ''),
                        'event_date_start': result_data.get('event_date_start', ''),
                        'continent': result_data.get('continent', ''),
                        'country': result_data.get('country', ''),
                        'city': result_data.get('city', ''),
                        'frequency': result_data.get('frequency', ''),
                        'industry': result_data.get('industry', ''),
                        'organizer': result_data.get('organizer', ''),
                        'organizer_en': result_data.get('organizer_en', ''),
                        'contact_info': result_data.get('contact_info', ''),
                        'exhibition_hall': result_data.get('exhibition_hall', ''),
                        'exhibition_hall_english': result_data.get('exhibition_hall_english', ''),
                        'exhibit_scope': result_data.get('exhibit_scope', ''),
                        'description': result_data.get('description', ''),
                        'ufi_certified': result_data.get('ufi_certified', 0),
                        'exhibition_area': result_data.get('exhibition_area', ''),
                        'ai_checked_status': result_data.get('ai_checked_status', 5),
                        'ai_link_status': result_data.get('ai_link_status', 0),
                        'ai_link': result_data.get('ai_link', ''),
                        'ai_link_time': result_data.get('ai_link_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S')),
                        'chinese_name': chinese_name  # WHERE条件的参数
                    }
                    
                    # 执行更新
                    with db.engine.connect() as conn:
                        with conn.begin():
                            conn.execute(update_sql, update_data)
                        # 事务会在with语句结束时自动提交，不需要手动调用commit
                    print("数据库更新成功")
                    return {"status": True, "data": result_data}
                except Exception as e:
                    print(f"数据库更新失败: {str(e)}")
                    _update_ai_status_failed(chinese_name, f"数据库更新失败: {str(e)}")
                    return {"status": False, "error": f"数据库更新失败: {str(e)}"}
                    
            except Exception as e:
                error_msg = f"处理AI检查结果时出错: {str(e)}"
                print(error_msg)
                _update_ai_status_failed(chinese_name, error_msg)
                return {"status": False, "error": error_msg}
        else:
            # AI补全失败，更新状态为失败
            error_msg = f"AI补全创建失败: {check_result.get('error', '未知错误')}"
            print(error_msg)
            _update_ai_status_failed(chinese_name, error_msg)
            return {"status": False, "error": error_msg}
            
    except Exception as e:
        error_msg = f"处理记录时发生错误: {str(e)}"
        print(error_msg)
        try:
            _update_ai_status_failed(chinese_name, error_msg)
        except:
            pass
        
        # 如果不是最后一次重试，则重试任务
        if self.request.retries < self.max_retries:
            print(f"任务失败，将在60秒后重试 (重试次数: {self.request.retries + 1}/{self.max_retries})")
            self.retry(exc=e, countdown=60)
            
        return {"status": False, "error": error_msg}
        
def _update_ai_status_failed(chinese_name, error_message):
    """辅助方法：更新展会AI补全状态为失败"""
    try:
        update_sql = text("""
        UPDATE exhibitions 
        SET ai_checked_status = :status,
            error_check_description = :error_msg
        WHERE chinese_name = :chinese_name
        """)
        
        with db.engine.connect() as conn:
            # 使用事务来执行更新操作
            with conn.begin():
                conn.execute(update_sql, {
                    'status': 2,  # 2表示失败
                    'error_msg': error_message[:500] if error_message else "未知错误",  # 限制长度
                    'chinese_name': chinese_name
                })
            # 注意：在with语句结束时，事务会自动提交或回滚，不需要显式调用commit
    except Exception as e:
        print(f"更新失败状态时出错: {str(e)}")
        # 这里不抛出异常，因为这是一个辅助方法

@app.task
def multiply(x, y):
    return x * y

@app.task
def send_email(to, subject, body):
    # 模拟发送邮件
    print(f"Sending email to {to} with subject '{subject}'")
    print(f"Body: {body}")
    return True


@app.task(bind=True, max_retries=3)
def process_file(self, file_path):
    try:
        # 模拟文件处理
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File {file_path} not found")

        with open(file_path, 'r') as f:
            content = f.read()

        return len(content)

    except FileNotFoundError as exc:
        # 重试
        try:
            self.retry(exc=exc, countdown=60)  # 60秒后重试
        except MaxRetryError:
            return f"Max retries exceeded for file {file_path}"

@app.task(name='ai_completion_exhibition_task', bind=True, max_retries=3)
def ai_completion_exhibition_task(self, exhibition_id):
    """AI补全展会信息的异步任务"""
    try:
        print(f"开始AI补全展会任务 - 展会ID: {exhibition_id}")
        result = process_exhibition(exhibition_id)
        
        if not result:
            print(f"AI补全展会ID {exhibition_id} 失败，这是第 {self.request.retries + 1} 次尝试")
            # 添加递增的重试延迟: 60秒, 120秒, 240秒...
            retry_delay = 60 * (2 ** self.request.retries)
            raise self.retry(countdown=retry_delay, exc=Exception(f"AI补全展会ID {exhibition_id} 失败"))
        
        print(f"AI补全展会ID {exhibition_id} 成功完成")
        return True
        
    except Exception as e:
        print(f"AI补全展会任务异常: {str(e)}")
        # 如果已经重试3次，记录最终失败
        if self.request.retries >= self.max_retries:
            print(f"AI补全展会ID {exhibition_id} 经过 {self.max_retries + 1} 次尝试后最终失败")
            # 尝试更新状态为失败
            try:
                from app.ai_models.ai_completion.ai_completion_exhibition import MySQLHelper
                mysql = MySQLHelper()
                mysql.update_ai_status(exhibition_id, f"AI补全最终失败: {str(e)[:100]}")
            except Exception as db_error:
                print(f"无法更新展会ID {exhibition_id} 的失败状态: {str(db_error)}")
        # 继续抛出异常以便Celery可以重试
        raise

